package vmap

import (
	"encoding/json"
	"errors"
	"sort"
)

type SliceV struct {
	slicev []V
}

var ErrTooLarge = errors.New("vmap.SliceV: too large")
var ErrOutofIndex = errors.New("vmap.SliceV: out of index")

const maxInt = 2 << 10

func (sv *SliceV) Sort()    { sort.Sort(sv) }
func (sv *SliceV) Len() int { return len(sv.slicev) }
func (sv *SliceV) Less(i, j int) bool {
	return sv.slicev[i].VInt("id") < sv.slicev[j].VInt("id")
}

func (sv *SliceV) Swap(i, j int) { sv.slicev[i], sv.slicev[j] = sv.slicev[j], sv.slicev[i] }

func (sv *SliceV) Cap() int { return cap(sv.slicev) }

func NewSliceV(n int) *SliceV {
	return &SliceV{
		slicev: make([]V, 0, n),
	}
}

func (sv *SliceV) Get(n int) (V, error) {
	if n >= sv.Len() {
		return nil, ErrOutofIndex
	}
	return sv.slicev[n], nil
}

func (sv *SliceV) Slices() []V {
	return sv.slicev
}

func (sv *SliceV) String() string {
	data, _ := json.Marshal(sv.slicev)
	return string(data)
}

func (sv *SliceV) MarshalJSON() ([]byte, error) {
	data, err := json.Marshal(sv.slicev)
	return data, err
}

func (sv *SliceV) grow(n int) int {
	l := len(sv.slicev)
	cl := cap(sv.slicev)
	if l+n > cl {
		if cl >= maxInt {
			panic(ErrTooLarge)
		}
		newlen := (cl + 1) * 2
		if cl > 1024 {
			newlen = cl + int(cl/4)
		}
		if newlen > maxInt {
			newlen = maxInt
		}
		vs := make([]V, newlen)
		copy(vs, sv.slicev)
		sv.slicev = vs
	}
	sv.slicev = sv.slicev[:l+n]
	return l
}

func (sv *SliceV) Grow(n int) {
	m := sv.grow(n)
	sv.slicev = sv.slicev[:m]
}

func (sv *SliceV) Write(v ...V) (n int, err error) {
	m := sv.grow(len(v))
	return copy(sv.slicev[m:], v), nil
}
